// tuple2.h
// Written by Sergei Sokov

#ifndef __TUPLE2_H
#define __TUPLE2_H

#include <math.h>          // fabs()

template<class T>
class Tuple2_ {
 public:
  T x,y;

  // Constructors
  Tuple2_(void) { }
  Tuple2_(T xx, T yy) { x=xx; y=yy; }
  Tuple2_(const T *a) { x=a[0]; y=a[1]; }
  Tuple2_(const Tuple2_ &t) { x=t.x; y=t.y; }

  // "compare" function (required by some Sokov's templates)
  static int compare(const void *p1, const void *p2) {
    Tuple2_ *t1 = (Tuple2_*)p1;
    Tuple2_ *t2 = (Tuple2_*)p2;
    if(t1->x!=t2->x) return (t1->x<t2->x) ? -1 : +1;
    if(t1->y!=t2->y) return (t1->y<t2->y) ? -1 : +1;
    return 0;
  }

  // Set
  void set(T xx, T yy) { x=xx; y=yy; }
  void set(const T *a) { x=a[0]; y=a[1]; }
  void set(const Tuple2_ &t) { x=t.x; y=t.y; }
  void set(T v) { x=y= v; }
  // Get
  void get(T *a) const { a[0]=x; a[1]=y; }
  void getNegate(T *a) const { a[0]=-x; a[1]=-y; }
  void get(Tuple2_ &t) const { t.x=x; t.y=y; }

  // Add
  void add(T v) { x+=v; y+=v; }
  void add(T xx, T yy) { x+=xx; y+=yy; }
  void add(const T *a) { x+=a[0]; y+=a[1]; }
  void add(const Tuple2_ &t) { x+=t.x; y+=t.y; }
  void add(const T *a, const T *b) { x=a[0]+b[0]; y=a[1]+b[1]; }
  void add(const Tuple2_ &t1, const Tuple2_ &t2) { x=t1.x+t2.x; y=t1.y+t2.y; }
  void addScaled(const Tuple2_ &t, T s) { x+=t.x*s; y+=t.y*s; }
  // Sub
  void sub(T xx, T yy) { x-=xx; y-=yy; }
  void sub(const T *a) { x-=a[0]; y-=a[1]; }
  void sub(const Tuple2_ &t) { x-=t.x; y-=t.y; }
  void sub(const T *a, const T *b) { x=a[0]-b[0]; y=a[1]-b[1]; }
  void sub(const Tuple2_ &t1, const Tuple2_ &t2) { x=t1.x-t2.x; y=t1.y-t2.y; }
  // Mul
  void mul(T xx, T yy) { x*=xx; y*=yy; }
  void mul(const T *a) { x*=a[0]; y*=a[1]; }
  void mul(const Tuple2_ &t) { x*=t.x; y*=t.y; }
  void mul(const T *a, const T *b) { x=a[0]*b[0]; y=a[1]*b[1]; }
  void mul(const Tuple2_ &t1, const Tuple2_ &t2) { x=t1.x*t2.x; y=t1.y*t2.y; }
  // Div (zero division may occur!)
  void div(T xx, T yy) { x/=xx; y/=yy; }
  void div(const T *a) { x/=a[0]; y/=a[1]; }
  void div(const Tuple2_ &t) { x/=t.x; y/=t.y; }
  void div(const T *a, const T *b) { x=a[0]/b[0]; y=a[1]/b[1]; }
  void div(const Tuple2_ &t1, const Tuple2_ &t2) { x=t1.x/t2.x; y=t1.y/t2.y; }

  // Negate
  void negate(void) { x=-x; y=-y; }
  void negate(const Tuple2_ &t) { x=-t.x; y=-t.y; }
  void negate(const T *a) { x=-a[0]; y=-a[1]; }

  // Scale
  void scale(T s) { x*=s; y*=s; }
  void scale(const Tuple2_ &t, T s) { x=t.x*s; y=t.y*s; }
  void scale(T s, const Tuple2_ &t) { x=t.x*s; y=t.y*s; }
  void scale(const T *a, T s) { x=a[0]*s; y=a[1]*s; }
  // Scale and Sub  ( * - )
  void scaleSub(T s, const Tuple2_ &t) { x=x*s-t.x; y=y*s-t.y; }
  void scaleSub(T s, const Tuple2_ &t1, const Tuple2_ &t2) {
    x=t1.x*s-t2.x; y=t1.y*s-t2.y;
  }
  // Scale and Add  ( * + )
  void scaleAdd(T s, const Tuple2_ &t) { x=x*s+t.x; y=y*s+t.y; }
  void scaleAdd(T s, const Tuple2_ &t1, const Tuple2_ &t2) {
    x=t1.x*s+t2.x; y=t1.y*s+t2.y;
  }
  void scaleAdd(T s, const Tuple2_ &t1, const T *t2) {
    x = s*t1.x + t2[0];
    y = s*t1.y + t2[1];
  }
  void scaleAdd(T s, const T *t1, const T *t2) {
    x = s*t1[0]+ t2[0];
    y = s*t1[1]+ t2[1];
  }



  // Absolute
  void absolute(void) { x=(T)fabs(x); y=(T)fabs(y); }
  void absolute(const Tuple2_ &t) { x=(T)fabs(t.x); y=(T)fabs(t.y); }

  // Equals
  int equals(T xx,T yy) const {
    return (x==xx)&&(y==yy);
  }
  int equals(const Tuple2_& t) const {
    return (x==t.x)&&(y==t.y); 
  }

  // Clamping
  void clamp(T mn, T mx) {
     if(x<mn) x=mn; else { if(x>mx) x=mx; }
     if(y<mn) y=mn; else { if(y>mx) y=mx; }
  }
  void clamp(T mn, T mx, const Tuple2_ &t) {
     if(t.x<mn) x=mn; else { if(t.x>mx) x=mx; else x=t.x; }
     if(t.y<mn) y=mn; else { if(t.y>mx) y=mx; else y=t.y; }
  }
  void clampMin(T v) { if(x<v) x=v; if(y<v) y=v; }
  void clampMin(T v, const Tuple2_ &t) {
    x = (t.x<v) ? v : t.x;
    y = (t.y<v) ? v : t.y;
  }
  void clampMax(T v) { if(x>v) x=v; if(y>v) y=v; }
  void clampMax(T v, const Tuple2_ &t) {
    x = (t.x>v) ? v : t.x;
    y = (t.y>v) ? v : t.y;
  }

  // Interpolate
  void interpolate(const T *t1, const T *t2, T alfa) {
    x = t1[0] + (t2[0]-t1[0])*alfa;
    y = t1[1] + (t2[1]-t1[1])*alfa;
  }
  void interpolate(const Tuple2_ &t1, const Tuple2_ &t2, T alfa) {
    x = t1.x + (t2.x-t1.x)*alfa;
    y = t1.y + (t2.y-t1.y)*alfa;
  }
  void interpolate(const Tuple2_ &t2, T alfa) {
    x += (t2.x-x)*alfa;
    y += (t2.y-y)*alfa;
  }


  /*
   * Assignment and comparision operators
   */

  int operator==(const Tuple2_& t1) const {
    return equals(t1);
  }

  int operator!=(const Tuple2_& t1) const {
    return !equals(t1);
  }

  Tuple2_& operator=(const Tuple2_& t1) {
    set(t1);
    return *this;
  }

  Tuple2_& operator+=(const Tuple2_& t1) {
    add(t1);
    return *this;
  }
  Tuple2_& operator-=(const Tuple2_& t1) {
    sub(t1);
    return *this;
  }
  Tuple2_& operator*=(T s) {
    scale(s);
    return *this;
  }
  Tuple2_& operator*=(const Tuple2_& t1) {
    mul(t1);
    return *this;
  }
  Tuple2_& operator/=(T s) {
    scale(1.0f / s);
    return *this;
  }
  Tuple2_& operator/=(const Tuple2_& t1) {
    div(t1);
    return *this;
  }
}; /* Tuple2_ */


/*
 * Other operators
 */
template <class T>
inline Tuple2_<T> operator+(const Tuple2_<T>& t1) {
  return t1;
}

template <class T>
inline Tuple2_<T> operator-(const Tuple2_<T>& t1) {
  return Tuple2_<T>(-t1.x, -t1.y);
}

template <class T>
inline Tuple2_<T> operator*(const Tuple2_<T>& t1, T s) {
  return Tuple2_<T>(t1.x*s, t1.y*s);
}

template <class T>
inline Tuple2_<T> operator*(T s, const Tuple2_<T>& t1) {
  return Tuple2_<T>(t1.x*s, t1.y*s);
}

template <class T>
inline Tuple2_<T> operator*(const Tuple2_<T>& t1, const Tuple2_<T>& t2) {
  return Tuple2_<T>(t1.x*t2.x, t1.y*t2.y);
}

template <class T>
inline Tuple2_<T> operator/(const Tuple2_<T>& t1, T s) {
  s = 1.0f / s;
  return Tuple2_<T>(t1.x*s, t1.y*s);
}

template <class T>
inline Tuple2_<T> operator/(const Tuple2_<T>& t1, const Tuple2_<T>& t2) {
  return Tuple2_<T>(t1.x/t2.x, t1.y/t2.y);
}

template <class T>
inline Tuple2_<T> operator+(const Tuple2_<T>& t1, const Tuple2_<T>& t2) {
  return Tuple2_<T>(t1.x+t2.x, t1.y+t2.y);
}

template <class T>
inline Tuple2_<T> operator-(const Tuple2_<T>& t1, const Tuple2_<T>& t2) {
  return Tuple2_<T>(t1.x-t2.x, t1.y-t2.y);
}


typedef Tuple2_<float>  Tuple2f;
typedef Tuple2_<double> Tuple2d;

#endif

/* eof */
